package com.example.fresh_market.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.ImageView;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.example.fresh_market.R;
import com.example.fresh_market.constants.StrConstant;
import com.example.fresh_market.request.ApiResponse;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import lombok.Data;

@Data
public class HttpUtil {
    public static final String HOST = "https://88m96g6177.goho.co/api";
    public static final String Auth = "Authorization";

    public static Response.ErrorListener getCommonErrorListener(Context context) {
        return error -> {
            if (error.networkResponse == null) {
                Log.e("", "", error);
                ToastUtil.showToast(context, "网络错误");
            } else {
                ApiResponse response = new Gson().fromJson(new String(error.networkResponse.data), ApiResponse.class);
                Log.e("", response.getMsg(), error);
                ToastUtil.showToast(context, response.getMsg());
            }
        };
    }

    public static void get(Context context, String url, Consumer<String> listener) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(StrConstant.CONFIG, Context.MODE_PRIVATE);
        String token = sharedPreferences.getString(StrConstant.TOKEN, "");
        sendRequest(Request.Method.GET, context, url, Map.of(HttpUtil.Auth, token), null, listener, getCommonErrorListener(context));
    }

    public static void get(Context context, String url, Map<String, String> headers, Consumer<String> listener) {
        sendRequest(Request.Method.GET, context, url, headers, null, listener, getCommonErrorListener(context));
    }

    public static void put(Context context, String url, Map<String, String> headers,
                           Map<String, String> params, Consumer<String> listener) {
        sendRequest(Request.Method.PUT, context, url, headers, params, listener, getCommonErrorListener(context));
    }

    public static void put(Context context, String url, Map<String, String> params, Consumer<String> listener) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(StrConstant.CONFIG, Context.MODE_PRIVATE);
        String token = sharedPreferences.getString(StrConstant.TOKEN, "");
        sendRequest(Request.Method.PUT, context, url, Map.of(Auth, token), params, listener, getCommonErrorListener(context));
    }

    public static void post(Context context, String url, Map<String, String> params,
                            Consumer<String> listener) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(StrConstant.CONFIG, Context.MODE_PRIVATE);
        String token = sharedPreferences.getString(StrConstant.TOKEN, "");
        sendRequest(Request.Method.POST, context, url, Map.of(Auth, token), params, listener, getCommonErrorListener(context));
    }

    public static void post(Context context, String url, Map<String, String> headers, Map<String, String> params,
                            Consumer<String> listener) {
        sendRequest(Request.Method.POST, context, url, headers, params, listener, getCommonErrorListener(context));
    }

    public static void delete(Context context, String url, Consumer<String> listener) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(StrConstant.CONFIG, Context.MODE_PRIVATE);
        String token = sharedPreferences.getString(StrConstant.TOKEN, "");
        sendRequest(Request.Method.DELETE, context, url, Map.of(Auth, token), null, listener, getCommonErrorListener(context));
    }

    public static <T> String getBatchDelUrl(String url, List<T> ids) {
        StringBuilder stringBuilder = new StringBuilder(url);
        stringBuilder.append("?");
        for (T id : ids) {
            stringBuilder.append("ids=").append(id).append("&");
        }
        return stringBuilder.substring(0, stringBuilder.length() - 1);
    }

    public static void delete(Context context, String url,
                              Map<String, String> headers,
                              Consumer<String> listener) {
        sendRequest(Request.Method.DELETE, context, url, headers, null, listener, getCommonErrorListener(context));
    }

    public static void delete(Context context, String url,
                              Map<String, String> headers, Runnable runnable) {
        delete(context, url, headers, response -> {
            ApiResponse apiResponse = new Gson().fromJson(response, ApiResponse.class);
            if (apiResponse.getCode() == 200) {
                runnable.run();
            } else {
                ToastUtil.showToast(context, apiResponse.getMsg());
            }
        });
    }

    public static void sendRequest(int method, Context context, String url, Map<String, String> headers,
                                   Map<String, String> params,
                                   Consumer<String> listener,
                                   Response.ErrorListener errorListener) {
        StringRequest request = new StringRequest(method, HOST + url, listener::accept, errorListener) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return headers == null ? super.getHeaders() : headers;
            }

            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params == null ? super.getParams() : params;
            }

            @Override
            protected Response<String> parseNetworkResponse(NetworkResponse response) {
                String parsed = new String(response.data, StandardCharsets.UTF_8);
                return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
            }
        };
        getRequestQueue(context).add(request);
    }


    public static void loadImage(ImageView image, String name, RequestOptions requestOptions) {
        Glide.with(image.getContext())
                .applyDefaultRequestOptions(requestOptions
                        .error(R.drawable.ic_add_border)
                        .fallback(R.drawable.ic_add_border))
                .load(HttpUtil.HOST + "/usr/index/" + name)
                .into(image);
    }

    public static void sendJsonRequest(Context context, int method, String url, String json, Consumer<JSONObject> callback) {
        sendJsonRequest(context, method, url, json, null, callback);
    }

    public static void sendJsonRequest(Context context, int method, String url, String json,
                                       Map<String, String> headers,
                                       Consumer<JSONObject> callback) {
        SharedPreferences preferences = context.getSharedPreferences(StrConstant.CONFIG, Context.MODE_PRIVATE);
        String token = preferences.getString(StrConstant.TOKEN, "");
        if (headers == null) {
            headers = Map.of(HttpUtil.Auth, token);
        } else {
            headers.put(HttpUtil.Auth, token);
        }
        try {
            JSONObject jsonObject = new JSONObject(json);
            final Map<String, String> finalHeaders = headers;
            JsonObjectRequest request = new JsonObjectRequest(method, HttpUtil.HOST + url,
                    jsonObject,
                    callback::accept,
                    HttpUtil.getCommonErrorListener(context)) {
                @Override
                public Map<String, String> getHeaders() {
                    return finalHeaders;
                }
            };
            getRequestQueue(context).add(request);
        } catch (JSONException e) {
            e.printStackTrace(System.err);
        }
    }

    public static RequestQueue getRequestQueue(Context context) {
        return Volley.newRequestQueue(context);
    }
}
